#ifndef xpack_io_event_poll
#define xpack_io_event_poll
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::io_event_poll::inc
#include"define/base_type.hpp"
#include"dumb/disable_copy.hpp"
#include"interface/can_callback.hpp"
#include"macro/xenum_and.hpp"
#include"macro/xenum_or.hpp"
#include"macro/xexport.hpp"
#include"macro/xforward.hpp"
#include"macro/xhand_over.hpp"
#include"macro/xnew.hpp"
#include"meta/has_cast.hpp"
#include"meta/integer_type.hpp"
#include"meta/is_right_ref.hpp"
#include"meta/remove_ref.hpp"
#include"net/tcp.hpp"
#include"net/udp.hpp"
#pragma pop_macro("xuser")

namespace mixc::io_event_poll::inc{
    template<class type_t>
    concept has_lend_handler = requires(type_t item, ::handler handler){
        handler = item.lend();
    };

    template<class type_t>
    concept can_cast_handler = inc::has_cast<::handler, type_t> or has_lend_handler<type_t>;

    enum special_state_t : u32{
        is_hand_over = 1u << 0,
    };
}

namespace mixc::io_event_poll::origin{
    // EPOLLIN = 0x001,
    // EPOLLPRI = 0x002,
    // EPOLLOUT = 0x004,
    // EPOLLRDNORM = 0x040,
    // EPOLLRDBAND = 0x080,
    // EPOLLWRNORM = 0x100,
    // EPOLLWRBAND = 0x200,
    // EPOLLMSG = 0x400,
    // EPOLLERR = 0x008,
    // EPOLLHUP = 0x010,
    // EPOLLRDHUP = 0x2000,
    // EPOLLEXCLUSIVE = 1u << 28,
    // EPOLLWAKEUP = 1u << 29,
    // EPOLLONESHOT = 1u << 30
    // EPOLLET = 1u << 31

    enum class event_poll_flag_t : uxx{
        when_readable           = uxx(0x0001),
        when_writeable          = uxx(0x0004),
        when_read_writeable     = uxx(0x0005),
        when_closed             = uxx(0x2018),
        when_any                = uxx(when_closed | when_read_writeable),
    };

    enum class event_poll_options_t : uxx{
        one_shot            = 1u << 30,
    };

    union event_poll_item{
        inc::tcp::client_item_v4   * client_v4;
        inc::udp::p2p_v4           * p2p_v4;

        operator inc::tcp::client_item_v4 &(){
            return *client_v4;
        }

        operator inc::udp::p2p_v4 &(){
            return *p2p_v4;
        }

        inc::tcp::sock_type_t type() const {
            return (*client_v4)->sock_type;
        }
    };

    xstruct(
        xname(event_poll),
        xpubb(inc::disable_copy),
        xprif(m_fd, ixx)
    )
        using final_t       = the_t;
        using wait_invoke   = inc::icallback<void(event_poll_item, event_poll_flag_t)>;
        using wait_invokex  = inc::icallback<loop_t(event_poll_item, event_poll_flag_t)>;
    public:
        xprops()
            xpubgetx(is_open, bool){
                xr{ return xthe.m_fd > 0; }
            };

            xpubgetx(is_closed, bool){
                xr{ return xthe.m_fd == 0; }
            };
        $

        xprops_operator()

    public:
        event_poll() : m_fd(-1){}
        event_poll(event_poll && self) : 
            m_fd(self.m_fd){
            self.m_fd = -1;
        }
       ~event_poll(){
            this->close();
        }

        xhand_over_with_close()

        bstate_t open();
        bstate_t close();

        template<inc::can_cast_handler handler_t>
        requires(inc::has_lend_handler<handler_t> == false or (inc::has_lend_handler<handler_t> and inc::is_right_ref<handler_t &&>))
        bstate_t append(handler_t && handler, event_poll_flag_t flag, event_poll_options_t option = {}){
            using remove_ref_t = inc::remove_ref<handler_t>;
            auto        special_state   = inc::special_state_t{};
            ::handler   ignore_destory{0};
            ::u08       dummy[sizeof(handler_t)];

            if constexpr (inc::has_lend_handler<remove_ref_t>){
                ignore_destory  = handler.lend();
            }
            else{
                ignore_destory  = handler;
            }

            // 支持转移所有权移动，而 epoll 无需实际所有权
            // 所以这里使用类型擦除 + 所有权剥夺机制，将外部 handler 的所有权交给此对象托管
            if constexpr (inc::is_right_ref<handler_t &&>){
                xnew(dummy) remove_ref_t(xforward(handler));
                special_state   = inc::special_state_t(special_state | inc::special_state_t::is_hand_over);
            }
            return this->operation(ignore_destory, 1/*add*/, u32(flag) | u32(option), special_state);
        }

        bstate_t remove(::handler handler){
            return this->operation(handler, 2/*del*/, 0);
        }

        bstate_t wait(wait_invoke const & callback){
            return this->wait(not_exist, callback);
        }

        bstate_t wait(u64 timeout_millisecond, wait_invoke const & callback){
            return this->wait_core(timeout_millisecond, [&](event_poll_item item, event_poll_flag_t flag){
                callback(item, flag);
                return loop_t::go_on;
            });
        }

        bstate_t wait(wait_invokex const & callback){
            return this->wait_core(not_exist, callback);
        }

    private:
        struct pair{
            u32 handler                 = 0;
            u32 handler_error   : 1     = 0;
            u32 is_one_shot     : 1     = 0;
            u32 is_hand_over    : 1     = 0;
            u32 reserved        : 29    = 0;

            operator u64(){
                return *u64p(this);
            }
        };

        bstate_t operation(::handler handler, int op, u32 events, inc::special_state_t special_state = {});
        bstate_t wait_core(u64 timeout_millisecond, wait_invokex const & callback);
    $
}

xenum_and(mixc::io_event_poll::origin::event_poll_flag_t)
xenum_or (mixc::io_event_poll::origin::event_poll_flag_t)
#endif

xexport_space(mixc::io_event_poll::origin)
